#include "SketchModel.h"
#include "solvers/ModelSolver.h"
#include "database/ConstraintDb.h"
#include "database/ParameterDb.h"
#include "database/PointDb.h"
#include "database/PrimitiveDb.h"
#include "basic/Coordinate.h"
#include "solvers/SpringSolver.h"


namespace common {

SketchModel::SketchModel() {

	setUpDataBases();
	setSolver(new SpringSolver());
}

void SketchModel::setUpDataBases(){

	pointDb = new PointDb();
	parameterDb = new ParameterDb();
	constraintDb = new ConstraintDb(pointDb,parameterDb);
	primitiveDb = new PrimitiveDb(pointDb,constraintDb);
}

void SketchModel::setSolver(ModelSolver* solver){
	modelSolver = solver;
}

void SketchModel::solve(){

	//prepare solver
	if(pointDb!=NULL){
		modelSolver->setPointDb(pointDb);
	}else {
		addMsg("E-RROR : PointDb pointer = null");
	}

	if(constraintDb!=NULL){
		modelSolver->setConstraintDb(constraintDb);
	}else {
		addMsg("E-RROR : ConstraintDb pointer = null");
	}

	if(primitiveDb!=NULL){
		modelSolver->setPrimitiveDb(primitiveDb);
	}else {
		addMsg("E-RROR : PrimitiveDb pointer = null");
	}

	if(parameterDb!=NULL){
		modelSolver->setParameterDb(parameterDb);
	}else {
		addMsg("E-RROR : ParameterDb pointer = null");
	}

	addMsg("OK : Solver prepared ");

	modelSolver->solve();
	//emit solved();
	//emit modelChanged()

	addMsg("OK : Model Solved");

	addMsg("Solver Messages");
	addMsg("************************");
	//emit freshMessages(const std::list<std::string>& messages)

	//emit freshMessages(modelSolver->getMessages());

}

void SketchModel::relax(){
	primitiveDb->relax();
}


void SketchModel::addLine(Coordinate c1,Coordinate c2){
	if(primitiveDb->addLine(c1,c2)!=NULL){
		addMsg("Line OK");
	}
}
// SLOTS
void SketchModel::addCircle(Coordinate c1,Coordinate c2){
	if(primitiveDb->addCircle(c1,c2)!=NULL){
		addMsg("Circle OK");
	}
}
void SketchModel::addSegment(std::list<Coordinate> cSet){
	if(primitiveDb->addSegment(cSet)!=NULL){
		addMsg("Segment OK");
	}
}
void SketchModel::pointAdjust(int i, Coordinate c1){
	pointDb->get(i)->setX(c1.x);
	pointDb->get(i)->setY(c1.y);
	pointDb->get(i)->resetAnchor();
}
void SketchModel::addConnectPoints(int k,int l){

	if(constraintDb->addConnectPoints(k,l)!=NULL){
		addMsg("Constraint OK");
	}
}
void SketchModel::addFixPoint(int k){

	if(constraintDb->addFixPoint(k)!=NULL){
		addMsg("Constraint OK");
	}
}
void SketchModel::addPerpendicular(int k,int l, int m,int n){

	if(constraintDb->addPerpendicular(k,l,m,n)!=NULL){
		addMsg("Constraint OK");
	}
}
void SketchModel::addHorizontal(int k,int l){

	if(constraintDb->addHorizontal(k,l)!=NULL){
		addMsg("Constraint OK");
	}
}
void SketchModel::addVertical(int k,int l){

	if(constraintDb->addVertical(k,l)!=NULL){
		addMsg("Constraint OK");
	}
}
void SketchModel::addParallel(int k,int l, int m,int n){
	if(constraintDb->addParallel(k,l,m,n)!=NULL){
		addMsg("Constraint OK");
	}
}
void SketchModel::addSameLength(int k,int l, int m,int n){
	if(constraintDb->addSameLength(k,l,m,n)!=NULL){
		addMsg("Constraint OK");
	}
}
void SketchModel::addDistance(int k,int l,skreal paramValue){
	if(constraintDb->addDistanec(k,l,paramValue)!=NULL){
		addMsg("Constraint OK");
	}
}
void SketchModel::addAngle(int k,int l,int m,int n,skreal paramValue){
	if(constraintDb->addAngle(k,l,m,n,paramValue)!=NULL){
		addMsg("Constraint OK");
	}
}
void SketchModel::addTangency(int k,int l,int m,int n){
	if(constraintDb->addTangency(k,l,m,n)!=NULL){
		addMsg("Constraint OK");
	}
}

void SketchModel::removePrimitive(int id){

	if(primitiveDb->isId(id)){
		primitiveDb->remove(id);
	}
}

//END SLOTS

void SketchModel::removeConstraint(int id){
	if(constraintDb->isId(id)){
		constraintDb->remove(id);
	}
}

void SketchModel::setParameter(int id,skreal value){
	if(parameterDb->isId(id)){
		parameterDb->get(id)->setValue(value);
	}
}

// TABLE DATA
std::map<int,std::string> SketchModel::getPrimitiveData(){
	_keyType* primitiveId = primitiveDb->getIds();

	std::map<int,std::string> out;
	for(_keyType::iterator it = primitiveId->begin(); it!= primitiveId->end() ; it++){
		out.insert(make_pair(*it,primitiveDb->get(*it)->getTypeToString()));
	}
	delete primitiveId;
	return out;
}
std::list<ConstraintData> SketchModel::getConstraintData(){
	_keyType* constraintID = constraintDb->getIds();

	std::list<ConstraintData> out;
	for(_keyType::iterator it = constraintID->begin(); it!= constraintID->end() ; it++){

		int id = *it;
		std::string type = constraintDb->get(*it)->getTypeToString();
		int k=0; int l=0; int m=0; int n=0; int par=0;
		if( constraintDb->get(*it)->getK()!=NULL){
			k = constraintDb->get(*it)->getK()->getId();
		}
		if( constraintDb->get(*it)->getL()!=NULL){
			l = constraintDb->get(*it)->getL()->getId();
		}
		if( constraintDb->get(*it)->getM()!=NULL){
			m = constraintDb->get(*it)->getM()->getId();
		}
		if( constraintDb->get(*it)->getN()!=NULL){
			n = constraintDb->get(*it)->getN()->getId();
		}
		if( constraintDb->get(*it)->getParameter()!=NULL){
			par = constraintDb->get(*it)->getParameter()->getId();
		}
		out.push_back(ConstraintData(type,id,k,l,m,n,par));
	}
	delete constraintID;
	return out;
}
std::map<int,skreal> SketchModel::getParameterData(){
	_keyType* parameterID = parameterDb->getIds();

	std::map<int,skreal> out;
	for(_keyType::iterator it = parameterID->begin(); it!= parameterID->end() ; it++){
		out.insert(make_pair(*it,parameterDb->get(*it)->getValue()));
	}
	delete parameterID;
	return out;
}

// GRAPHICS VIEW + above
std::map<int,Coordinate> SketchModel::getPrimitivePoints(int i){
	std::map<int,Coordinate> out;
	if(primitiveDb->isId(i)){
		std::list<Point*> pnts = primitiveDb->get(i)->getAllPoints();

		for(std::list<Point*>::iterator it= pnts.begin(); it!= pnts.end(); it++){
			out.insert(make_pair((*it)->getId(),Coordinate( (*it)->getX() , (*it)->getY() )));
		}

	}
	return out;
}


void SketchModel::addMsg(const std::string& msg){
	messages.push_back(msg);
}
std::string SketchModel::report(){
	std::string out;
	out.append("\n*****REPORT *****\n");
	out.append(primitiveDb->toString());
	out.append(constraintDb->toString());
	out.append(pointDb->toString());
	return out;
}

SketchModel::~SketchModel() {

	delete pointDb;
	delete parameterDb;
	delete constraintDb;
	delete primitiveDb;

}

}
